
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Vector;

import javax.jmdns.JmDNS;
import javax.jmdns.ServiceInfo;

/**
 * A simple class that opens a server socket, and prints each message received
 * to the console.
 * 
 * @author Graeme Stevenson (graeme.stevenson@ucd.ie)
 * @author Amended by Tom Crowe (09137149@ucdconnect.ie)
 */
public class OfficeServices {
	
	/**
	 * The service type you want to register. The first part should be a unique
	 * name to identify your services belonging to your project. The second part
	 * identifies the transport. The last part identifies the domain. Note that
	 * this must end with a period. Service types and transports typically begin
	 * with an underscore (e.g. _tcp or _udp). Each part is separated by a
	 * period. E.g. "printer._tcp.local.".
	 */
	private static final String SERVICE_TYPE = "OfficeServices._udp.local.";

	/**
	 * A unique name for the service you want to register; e.g.
	 * "casl_level3_colour".
	 */
	private static final String SERVICE_NAME = "OfficeServices";
	
	/**
	 * Accept a queue of this many connections. This offers protection against a
	 * SYN attack because once the queue is full, subsequent connection requests
	 * are rejected.
	 */
	private int my_backlog = 5;

	/**
	 * The server socket.
	 */
	private ServerSocket my_serverSocket;
	   
	/**
	 * The default server port.
	 */
	private static final int DEFAULT_PORT = 10987;

	/**
	 * A list of current businesses offering office services. This is a
	 * a multi-threaded server hence Vector, although it may be overkill
	 * because there are no updates expected after initial creation.
	 */
	private	Vector<Office> officeList = null;
   	
	
	/**
	 * Create the server socket.
	 * @param a_port the port that the server socket should listen on.
	 */
	public OfficeServices(int a_port) throws IOException {

		initialiseOfficeList();
		
		try {
			my_serverSocket = new ServerSocket(a_port, my_backlog);
			System.out.println("TCP socket listening on port " + a_port);
		} catch (SecurityException se) {
			se.printStackTrace();
		}
	}

	
	/**
	 * Listens on the server socket forever and spawn a thread to handle each
	 * new accepted connection. The new thread takes care of the processing
	 * and the main thread can return to accept new connections asap.
	 * 
	 */
	public void listen() {
		
		Socket socket = null;
		while (true) {
			try {
				
				socket = my_serverSocket.accept();
				(new WorkerThr(socket, officeList)).start();
			}
			catch (IOException ioe) {
				ioe.printStackTrace();
			}
		}
	}
	
		
	/**
	 * Parses the cmd-line arguments, creates the server socket, registers
	 * the service with mDNS and then listens for connections ad infinitum.
	 * @param args the program arguments. Should take the form &lt;port&gt;
	 */
	public static void main(String[] args) throws IOException{
		int port = 0;
		OfficeServices server = null;

		port = checkArgs(args);
		
		// Create the server before registering service in case there 
		// is a port clash for my server
		try {
			server = new OfficeServices(port);
		} catch (IOException ioe) {
			System.err.println("The server could not be started - possibly port clash on port: " + port);
			ioe.printStackTrace();
			System.exit(1);
		}
		
		// Register this service with jmDns (zeroconf impl)
		JmDNS jmdns = JmDNS.create();
		ServiceInfo info = 
			ServiceInfo.create(SERVICE_TYPE, SERVICE_NAME, port, 0, 0, "a_property=some_value");
		jmdns.registerService(info);
		System.out.println("Registered Service as " + info); 
		
		// Listen on the server socket. This will run until the program is killed.
		server.listen();

		// Clean up jmDns registration
		jmdns.unregisterService(info);
		jmdns.close();

		// Clean up server socket
		server.my_serverSocket.close();

	}
	
	/**
	 * Parses and processes the command line arguments.
	 * @param args   the program arguments. Should take the form &lt;port&gt;
	 * @return port  the port value on which to set up the listening server socket
	 */
	private static int checkArgs(String[] args) {

		int port = 0;
		// Check we have the right number of arguments and parse
		if (args.length == 1) {
			try {
				port = Integer.valueOf(args[0]);
			} catch (NumberFormatException nfe) {
				System.err.println("The value provided for the port is not an integer");
				nfe.printStackTrace();
				System.exit(1);
			}
			if (port < 1){
				System.err.println("The values provided for the port must be > 0");
				System.exit(1);
			}
		}
		if (args.length == 0)
			port = DEFAULT_PORT;
		else {
			System.out.println("Usage: java OfficeServices <port (optional)>");
			System.out.println("Default port: " + DEFAULT_PORT);
			System.exit(1);
		}
		return port;
	}
	
	
	/**
	 * Initialise the server with a list of dummy offices and their services.
	 */
	private void initialiseOfficeList() {
		
		// Establish some Office obj's and services.
		Office tmp = null;
		officeList = new Vector<Office>();
		
		tmp = new Office(1, "Office Extra", "Terminal B (Near Gate 28)", 
				"+353-1-2989837", "info@officeExtra.ie","TermB.gif");
		tmp.addOfficeService(Office.PRINTING);
		tmp.addOfficeService(Office.PHOTOCOPY);
		tmp.addOfficeService(Office.OFFICE_SUPPLIES);
		tmp.addOfficeService(Office.LOGO_DESIGN);
		tmp.addOfficeService(Office.LARGE_FORMAT_AND_POSTERS);
		tmp.addOfficeService(Office.PROMOTIONAL_PRODUCTS);
		tmp.addOfficeService(Office.PHOTO_PRINT);
		officeList.add(tmp);
		
		tmp = new Office(2, "Copy Plus", "Terminal D (Next to Duty-Free check-out)", 
				"+353-1-2949149", "service@copyplus.ie","TermB.gif");
		tmp.addOfficeService(Office.PRINTING);
		tmp.addOfficeService(Office.LEAFLETS_FLYERS);
		tmp.addOfficeService(Office.LOGO_DESIGN);
		tmp.addOfficeService(Office.PHOTOCOPY);
		tmp.addOfficeService(Office.PROMOTIONAL_PRODUCTS);
		tmp.addOfficeService(Office.CORPORATE_CHRISTMAS_CARDS);
		tmp.addOfficeService(Office.INTERNET);
		officeList.add(tmp);
		
		tmp = new Office(3, "Photo Magic", "Terminal E (Beside Restaurant area)", 
				"+353-1-0948020", "guest@photomagic.ie","TermB.gif");
		tmp.addOfficeService(Office.PRINTING);
		tmp.addOfficeService(Office.PHOTOCOPY);
		tmp.addOfficeService(Office.OFFICE_SUPPLIES);
		tmp.addOfficeService(Office.LARGE_FORMAT_AND_POSTERS);
		tmp.addOfficeService(Office.STATIONERY);
		tmp.addOfficeService(Office.PROMOTIONAL_PRODUCTS);
		tmp.addOfficeService(Office.PHOTO_PRINT);
		tmp.addOfficeService(Office.INTERNET);
		officeList.add(tmp);
		
		tmp = new Office(4, "Indelible", "Main Arrivals Hall (In front of check-in area B)", 
				"+353-1-4873094", "info@indelible.ie","TermB.gif");
		tmp.addOfficeService(Office.PRINTING);
		tmp.addOfficeService(Office.PHOTOCOPY);
		tmp.addOfficeService(Office.LOGO_DESIGN);
		tmp.addOfficeService(Office.LARGE_FORMAT_AND_POSTERS);
		tmp.addOfficeService(Office.STATIONERY);
		tmp.addOfficeService(Office.PROMOTIONAL_PRODUCTS);
		tmp.addOfficeService(Office.PHOTO_PRINT);
		tmp.addOfficeService(Office.INTERNET);
		officeList.add(tmp);
		
	}
	
} // end class
